<!DOCTYPE html>
<html lang="en">
    <head>
            <meta charset="utf-8">
            <meta http-equiv="X-UA-Compatible" content="IE=edge">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            
            
            
            <link rel="shortcut icon" href="../../img/favicon.ico">
        
        <script type="text/javascript" src="//game.bmob.cn/static/doc_union.js"></script>
            <title>Bmob文档中心</title>
            <link href="../../css/bootstrap-custom.min.css" rel="stylesheet">
            <link href="../../css/font-awesome-4.5.0.css" rel="stylesheet">
            <link href="../../css/base.css" rel="stylesheet">
            <link rel="stylesheet" href="../../css/highlight.css">
            <link href="../../css/agate.css" rel="stylesheet">
            <link href="../../css/custom.css" rel="stylesheet" id="custom">
    </head>

    <body >

        <div class="navbar navbar-fixed-top" role="navigation">
    <div class="main-nav">
        <!-- Collapsed navigation -->
        <div class="navbar-header">
            <a class="navbar-brand" href="../..">
                <!--Bmob文档中心-->
                <img src="../../img/logo.png" alt="">
            </a>
        </div>

        <!-- Expanded navigation -->
        <div class="navbar-collapse collapse">

          <ul class="nav navbar-nav">
            
              <li class="pull-left">
                
					<a href="../..">文档首页</a>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="">数据服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">数据服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li >
									<a href="../../data/android/">Android</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/ios/">iOS</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/csharp/">C#</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/php/">PHP</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/go/">GO</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/restful/">RESTful</a>
                                </li>
                            
                            
								<li >
									<a href="../../data/javascript/">JavaScript</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../../data/cocos2d_x/">Cocos2D-X</a>
                                </li>
							
                            
								<li >
									<a href="../../data/wechat_app/">小程序</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">快应用</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">Nodejs</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../data/wechat_app_new/">Cocos Creator</a>
                                </li>
							
                            
								<li >
									<a href="../../data/wechat_app_new/rm/">小程序(新)</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../cloud_function/android/">云函数</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">云函数 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../cloud_function/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/java/">Java</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/csharp/">C#</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../cloud_function/restful/">RESTful</a>
                                </li>
							
                            
								<li >
									<a href="../../cloud_function/web/">Web</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../sms/android/">短信服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">短信服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../sms/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../sms/restful/">RESTful</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left active">
                
					<!--<a href="">游戏实时后端</a>-->
					<li class="dropdown active">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">游戏实时后端 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li >
									<a href="../unity/quick_start/">Unity</a>
                                </li>
                            
                            
								<li >
									<a href="../cocos_creator/quick_start/">Cocos Creator</a>
                                </li>
                            
                            
								<li >
									<a href="../wechat_games/quick_start/">微信小游戏</a>
                                </li>
                            
                            
                                <li >
                                    <a href="../cloud_function/develop_doc/">云函数</a>
                                </li>
							
                            
                                <li class="active">
                                    <a href="./">经典案例</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="">IM服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">IM服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
								<li >
									<a href="../../im/android/">Android</a>
                                </li>
                            
                            
								<li >
									<a href="../../im/ios/">iOS</a>
                                </li>
                            
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../push/android/">推送服务</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">推送服务 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../push/android/">Android</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/ios/">iOS</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/php/">PHP</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/javascript/">JavaScript</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../push/restful/">RESTful</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li class="pull-left">
                
					<!--<a href="../../other/common_problem/">其他</a>-->
					<li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">其他 <b class="caret"></b></a>
                        <ul class="dropdown-menu">
                            
                                <li >
                                    <a href="../../other/common_problem/">常见问题</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/error_code/">错误码</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/data_safety/">数据安全</a>
                                </li>
							
                            
                                <li >
                                    <a href="../../other/bql/">BQL</a>
                                </li>
							
                        </ul>
                    </li>
                
              </li>
            
              <li>
                  <a href="https://www.bmob.cn/repository/index" target="_blank">知识库</a>
              </li>
              <li>
                  <a href="http://doc.bmob.cn/video/index.html" target="_blank">视频教程</a>
              </li>
            </ul>
            
        </div>
    </div>
</div>

        <div class="pagebody" id="main-wrapper">
            <div class="sidebar">
                <div class="bs-sidebar hidden-print affix well" role="complementary">

	
		
	
		
				
				
				
				
				
				
				
				
				
				
				
				
				
		
	
		
				
				
				
				
				
				
				
				
		
	
		
				
				
				
				
				
		
	
		
				
				
				
				
				
					<div class="code-title">经典案例</div>
				
		
	
		
				
				
		
	
		
				
				
				
				
				
		
	
		
				
				
				
				
		
	


	<ul class="nav bs-sidenav">
		
			
		
			
		
			
		
			
		
			
				
					
						
					
						
					
						
					
						
					
						
							
								
									
										<li class="active "><a href="#_1">吃鸡游戏</a>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_2">步骤</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_3">开发体验</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_5">玩家属性配置</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_6">云端代码</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_7">代码节选</a></li>
											</ul>
											
										</li>
									
										<li class=""><a href="#_8">打怪游戏改造</a>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#unity">准备一个单机的Unity游戏</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_9">开始改造</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#bmob-game-sdk">结合Bmob Game Sdk</a></li>
											</ul>
											
										</li>
									
										<li class=""><a href="#_10">五子棋/象棋匹配对战</a>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#1">1.获取 比目游戏云服务 (下称 官网)的账号；</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#2-sdk">2. 在官网下载 微信小游戏SDK，导入到原有的单机下棋项目中；</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#3-sdk-appkey">3. 初始化sdk，第一个参数修改为官网获取的 AppKey，第二个参数可先不填，要做第四个步骤获得。</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#4-bgsinstanceinit">4. 创建房间，获得Bgs.instance.Init的第二个参数 ###</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#5">5. 加入房间，初始化监听器</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#6">6. 实现下棋数据的实时交互</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#7">7. 实现云端代码逻辑</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#8">8. 离开房间</a></li>
											</ul>
											
										</li>
									
										<li class=""><a href="#_11">贪吃蛇大作战</a>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_12">链接</a></li>
											</ul>
											
											<ul class="nav nav-l2">
												<li><a class="itm-l2" href="#_13">二维码</a></li>
											</ul>
											
										</li>
									
								
							
						
					
				
			
		
			
		
			
		
			
		
	</ul>
</div>
            </div>
            <div class="content" role="main">
                <div class="wrap">
                    

<h2 id="_1">吃鸡游戏<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<h3 id="_2">步骤<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h3>
<ol>
<li>要看懂此案例，首先，你得有一定的<code>Unity</code>开发功底，以及入门级的<code>Java</code>语法;</li>
<li>访问 Unity 的 <a href="https://assetstore.unity.com/">Asset Store</a> 下载一个射击类游戏项目，并且 <code>Import</code> 到 Unity 内;</li>
<li>将 <code>BmobGame_UnitySDK_vx.x.x_xxxxxx.unitypackage</code> Import 到Unity内;</li>
<li>修改SDK，将游戏开始跳转的 Scene 改为你下载的射击类游戏 Demo Scene;</li>
<li>在 Demo Scene 进行SDK的初始化，绑定 <code>delegate</code> 用于处理各种通知;</li>
<li>将本地角色 <code>LocalPlayer</code> 的移动、面向角度、姿态(卧倒/下蹲/持有手枪/持有步枪)等数据，调用SDK接口同步到服务器;</li>
<li>将 <code>LocalPlayer</code> 的瞬时动作(如开火/跳跃/换弹匣、拾取物品等Pose)通过SDK接口直接发送到其它玩家;</li>
<li>击中其它玩家时，将事件详情通知到服务器云端代码，包括所用武器、击中身体部位、对方的id;</li>
<li>读取服务器同步的数据，修改 <code>LocalPlayer</code> 的血量、击杀数、名次，并渲染其它玩家的位置、角度、姿态。获取其它玩家直接发送的瞬时动作，操作Animator;</li>
<li>在 <code>BGS官网</code> 登录管理后台，创建游戏，修改 <code>服务器运行配置</code> ，包括 <code>每秒帧率</code>(默认60Hz)、<code>房间最多玩家数</code> (2个或以上);</li>
<li>修改 <code>玩家属性配置</code>，设置各个属性的名称、类型、长度、值域、由云端/客户端编辑、其它玩家是否可见等。下方有 <code>PUBG</code> 的玩家属性例子;</li>
<li>打开 <code>Eclipse</code> 或 <code>Android Studio</code>，创建Java项目，导入 <code>BmobGame_JavaCloud_vx.x.x_xxxxxx.jar</code>，并创建 <code>Player.java</code> 和 <code>Room.java</code>，分别继承自 <code>PlayerBase.class</code> 和 <code>RoomBase.class</code> 后，编写游戏逻辑代码。下方有案例;</li>
<li>打包运行游戏，就可以多人同时在线对战啦~</li>
</ol>
<h3 id="_3">开发体验<a class="headerlink" href="#_3" title="Permanent link">&para;</a></h3>
<p>但是在基于客户端基本完工的情况下，接入BGS，把它从一个单机游戏变成了多人联网游戏，仅花费1小时。马上就可以多人开黑啦。</p>
<hr />
<h4 id="_4">运行效果<a class="headerlink" href="#_4" title="Permanent link">&para;</a></h4>
<p><a href="https://www.bilibili.com/video/av20272527/">Demo测试运行视频 (B站无广告传送门) </a></p>
<p><em>超清/720P模式观看体验更好哦</em></p>
<iframe height=498 width=1020 src='//player.youku.com/embed/XMzQzNDYyODkzNg==' frameborder=0 'allowfullscreen'></iframe>

<p>可以说除了动作不完善之外，联网射击对战游戏基本上的要素都具备啦</p>
<hr />
<h3 id="_5">玩家属性配置<a class="headerlink" href="#_5" title="Permanent link">&para;</a></h3>
<p>玩家的属性有以下几种类型：</p>
<table>
<thead>
<tr>
<th align="center">类型</th>
<th align="center">使用案例</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">boolean</td>
<td align="center">是否无敌状态</td>
</tr>
<tr>
<td align="center">int</td>
<td align="center">血量、分数</td>
</tr>
<tr>
<td align="center">float</td>
<td align="center">2D游戏的面朝角度</td>
</tr>
<tr>
<td align="center">double</td>
<td align="center">吟唱读条进度</td>
</tr>
<tr>
<td align="center">boolean[]</td>
<td align="center">各种持续姿态</td>
</tr>
<tr>
<td align="center">int[]</td>
<td align="center">物品栏、外观项</td>
</tr>
<tr>
<td align="center">float[]</td>
<td align="center">角色位置、3D游戏的面朝角度</td>
</tr>
<tr>
<td align="center">double[]</td>
<td align="center">高物理精度游戏的部分参数</td>
</tr>
</tbody>
</table>
<p><em>当属性类型为 <code>int</code>、 <code>int[]</code>时，需要指定最大值 <code>max</code>，以便服务器优化同步效率</em></p>
<p><em>当属性类型为 <code>xxx[]</code> 时，需要指定数组长度 <code>count</code>，以便服务器优化同步效率</em></p>
<hr />
<p>每个玩家属性还有 <code>export</code>、<code>editable</code> 两个开关，默认都为false，以下是这两个开关的描述:</p>
<p><strong>Export</strong> :</p>
<table>
<thead>
<tr>
<th align="center">值</th>
<th align="center">效果</th>
<th align="center">使用案例</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">true</td>
<td align="center">该玩家属性对所有玩家开放</td>
<td align="center">位置、角度、姿态、外观项</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">该玩家属性仅本玩家可获取</td>
<td align="center"><code>PUBG</code>的血量、击杀数等</td>
</tr>
</tbody>
</table>
<p><strong>Editable</strong> :</p>
<table>
<thead>
<tr>
<th align="center">值</th>
<th align="center">效果</th>
<th align="center">使用案例</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">true</td>
<td align="center">该值由客户端进行修改，服务器只读</td>
<td align="center">位置、角度、姿态</td>
</tr>
<tr>
<td align="center">false</td>
<td align="center">该值由服务器进行修改，客户端只读</td>
<td align="center"><code>PUBG</code>的血量、击杀数等</td>
</tr>
</tbody>
</table>
<p><em>一个属性不能同时 Export==false 且 Editable==True，因为这种属性往往不需要经过网络</em></p>
<hr />
<p>以下是 <code>PUBG</code> 的推荐玩家属性配置</p>
<table>
<thead>
<tr>
<th align="center">名称</th>
<th align="center">类型</th>
<th align="center">最大值/数组长度</th>
<th align="center">Export</th>
<th align="center">Editable</th>
<th align="center">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">hp</td>
<td align="center">int</td>
<td align="center">100 / -</td>
<td align="center">false</td>
<td align="center">false</td>
<td align="center">血量</td>
</tr>
<tr>
<td align="center">score</td>
<td align="center">int</td>
<td align="center">100 / -</td>
<td align="center">false</td>
<td align="center">false</td>
<td align="center">击杀数</td>
</tr>
<tr>
<td align="center">position</td>
<td align="center">float[]</td>
<td align="center">- / 3</td>
<td align="center">true</td>
<td align="center">true</td>
<td align="center">位置</td>
</tr>
<tr>
<td align="center">rotation</td>
<td align="center">float[]</td>
<td align="center">- / 3</td>
<td align="center">true</td>
<td align="center">true</td>
<td align="center">角度</td>
</tr>
<tr>
<td align="center">surface</td>
<td align="center">int[]</td>
<td align="center">255 / 8</td>
<td align="center">true</td>
<td align="center">true</td>
<td align="center">外观件</td>
</tr>
<tr>
<td align="center">knapsack</td>
<td align="center">int[]</td>
<td align="center">65535 / 255</td>
<td align="center">false</td>
<td align="center">false</td>
<td align="center">物品栏</td>
</tr>
</tbody>
</table>
<pre><code>    案例中的 knapsack(背包)，设计原理是index为物品id，对应数字为物品个数
    例如游戏中共有3种道具，分别是枪、子弹、手雷，我们定它们的id分别为0、1、2
    那么knapsack为[1,8,4]意味着这个玩家有 1把枪、8颗子弹、4颗手雷

    这个属性之所以Editable为false，是为了防止客户端外挂可以随意编辑生成道具
    取而代之的是客户端发送拾取、消耗、丢弃道具的指令到云端代码，经由合法性判断后操作该属性、同步到客户端
</code></pre>
<hr />
<h3 id="_6">云端代码<a class="headerlink" href="#_6" title="Permanent link">&para;</a></h3>
<ul>
<li>BGS的云端代码可以完美实现游戏的后端逻辑层，并且有热更新机制，可以随时修改、升级</li>
<li>缝合了Bmob数据服务，可以快速进行Bmob数据库的增删查改，其中 <code>Bmob.class</code> 的用法与 <a href="http://doc.bmob.cn/cloud_function/java/">Bmob Java云函数</a> 的 <code>modules.oData</code> 完全一致</li>
</ul>
<p>主要需要开发者实现的有 <code>Room.java</code>、<code>Player.java</code></p>
<hr />
<h4 id="roomjava"><strong>Room.java</strong><a class="headerlink" href="#roomjava" title="Permanent link">&para;</a></h4>
<p>继承自 <code>RoomBase.class</code> , 作用是管理、监控房间的生命周期</p>
<p><strong>以下是类属性</strong> ：</p>
<table>
<thead>
<tr>
<th align="center">名称</th>
<th align="center">类型</th>
<th align="center">作用</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">roomId</td>
<td align="center">int</td>
<td align="center">房间id，创建房间时产生，客户端SDK加入房间时需要携带</td>
</tr>
<tr>
<td align="center">players</td>
<td align="center">Player.class[]</td>
<td align="center">该房间内所有玩家</td>
</tr>
<tr>
<td align="center">playerCount</td>
<td align="center">int</td>
<td align="center">该房间内玩家数</td>
</tr>
<tr>
<td align="center">masterId</td>
<td align="center">String</td>
<td align="center">创建房间的玩家id</td>
</tr>
<tr>
<td align="center">masterKey</td>
<td align="center">String</td>
<td align="center">销毁/踢出玩家需要携带的key</td>
</tr>
<tr>
<td align="center">joinKey</td>
<td align="center">String</td>
<td align="center">加入房间需要携带的key</td>
</tr>
<tr>
<td align="center">isPlaying</td>
<td align="center">boolean</td>
<td align="center">该房间是在游戏中还是等待中</td>
</tr>
<tr>
<td align="center">startTime</td>
<td align="center">long</td>
<td align="center">该房间的游戏开始时间毫秒数</td>
</tr>
</tbody>
</table>
<p><strong>以下是可主动调用的方法</strong> ：</p>
<table>
<thead>
<tr>
<th align="center">方法名</th>
<th align="center">参数</th>
<th align="center">返回值</th>
<th align="center">作用</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">dispatchGameOver</td>
<td align="center">-</td>
<td align="center">-</td>
<td align="center">让房间游戏结束</td>
</tr>
<tr>
<td align="center">sendToAll</td>
<td align="center">byte[]</td>
<td align="center">boolean</td>
<td align="center">向所有玩家推送消息</td>
</tr>
<tr>
<td align="center">sendToAllExcept</td>
<td align="center">byte[],Player</td>
<td align="center">boolean</td>
<td align="center">向某玩家以外的所有玩家推送消息</td>
</tr>
</tbody>
</table>
<p><strong>以下是需要Override的生命周期相关监听方法</strong> ：</p>
<p><em>这些方法都没有参数，返回值均为void</em></p>
<table>
<thead>
<tr>
<th align="center">方法名</th>
<th align="center">调用时机</th>
<th align="center">使用案例</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">onCreate</td>
<td align="center">房间被创建时</td>
<td align="center">将房间的 <code>id</code>、<code>joinKey</code>等保存到 <code>Bmob数据库</code>，可进行好友对战、匹配对战</td>
</tr>
<tr>
<td align="center">onGameStart</td>
<td align="center">所有玩家均已准备，游戏开始时</td>
<td align="center">初始化物品数量和位置、安全区的位置</td>
</tr>
<tr>
<td align="center">onTick</td>
<td align="center">游戏中，以每秒多次的频率调用(取决于每秒帧率配置)</td>
<td align="center">实现安全区、轰炸区等游戏设定</td>
</tr>
<tr>
<td align="center">onDestroy</td>
<td align="center">房间被销毁时</td>
<td align="center">将房间信息从 <code>Bmob数据库</code> 删除</td>
</tr>
</tbody>
</table>
<hr />
<h4 id="playerjava"><strong>Player.java</strong><a class="headerlink" href="#playerjava" title="Permanent link">&para;</a></h4>
<p>继承自 <code>PlayerBase.class</code> , 作用有：
1. 管理、监控玩家的行为和生命周期
2. 修改玩家属性值(editable==false的属性)
3. 监听玩家属性值变动(editable==true的属性)</p>
<p><strong>以下是类属性</strong> ：</p>
<table>
<thead>
<tr>
<th align="center">名称</th>
<th align="center">类型</th>
<th align="center">作用</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">room</td>
<td align="center">Room</td>
<td align="center">房间对象</td>
</tr>
<tr>
<td align="center">no</td>
<td align="center">int</td>
<td align="center">玩家在该房间的id，加入房间时分配</td>
</tr>
<tr>
<td align="center">roommates</td>
<td align="center">Player.class[]</td>
<td align="center">该房间内所有玩家，可以用roommates[no]进行索引</td>
</tr>
</tbody>
</table>
<p><strong>以下是可主动调用的方法</strong> ：</p>
<table>
<thead>
<tr>
<th align="center">方法名</th>
<th align="center">参数</th>
<th align="center">返回值</th>
<th align="center">作用</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">syncToClient</td>
<td align="center">-</td>
<td align="center">void</td>
<td align="center">修改参数结束后，将修改同步到客户端</td>
</tr>
<tr>
<td align="center">getStatus</td>
<td align="center">-</td>
<td align="center">int</td>
<td align="center">获取玩家状态，有无人/等待/准备/游戏中/被淘汰/掉线</td>
</tr>
<tr>
<td align="center">getUserId</td>
<td align="center">-</td>
<td align="center">String</td>
<td align="center">加入房间时传入的用户id</td>
</tr>
<tr>
<td align="center">send</td>
<td align="center">byte[]</td>
<td align="center">boolean</td>
<td align="center">向本玩家推送消息</td>
</tr>
<tr>
<td align="center">sendToAll</td>
<td align="center">byte[]</td>
<td align="center">boolean</td>
<td align="center">向该房间的所有玩家推送消息</td>
</tr>
<tr>
<td align="center">sendToOthers</td>
<td align="center">byte[]</td>
<td align="center">boolean</td>
<td align="center">向本玩家以外的所有玩家推送消息</td>
</tr>
<tr>
<td align="center">kick</td>
<td align="center">-</td>
<td align="center">boolean</td>
<td align="center">将本玩家踢出房间</td>
</tr>
</tbody>
</table>
<p><strong>以下是需要Override的生命周期相关监听方法</strong> ：</p>
<p><em>这些方法都没有参数，返回值均为void</em></p>
<table>
<thead>
<tr>
<th align="center">方法名</th>
<th align="center">调用时机</th>
<th align="center">使用案例</th>
</tr>
</thead>
<tbody>
<tr>
<td align="center">onJoin</td>
<td align="center">玩家加入房间时</td>
<td align="center">操作Bmob数据库</td>
</tr>
<tr>
<td align="center">onLeave</td>
<td align="center">玩家主动退出房间时</td>
<td align="center">操作Bmob数据库</td>
</tr>
<tr>
<td align="center">onReady</td>
<td align="center">玩家在房间内准备时</td>
<td align="center">-</td>
</tr>
<tr>
<td align="center">onUnready</td>
<td align="center">玩家取消准备</td>
<td align="center">-</td>
</tr>
<tr>
<td align="center">onGameStart</td>
<td align="center">本轮游戏开始</td>
<td align="center">初始化玩家属性</td>
</tr>
<tr>
<td align="center">onTick</td>
<td align="center">游戏开始后以一定频率被调用</td>
<td align="center">更新安全区位置和半径、发送通知</td>
</tr>
<tr>
<td align="center">onGameOver</td>
<td align="center">游戏结束</td>
<td align="center">保存游戏记录到Bmob数据库</td>
</tr>
<tr>
<td align="center">onOffline</td>
<td align="center">玩家掉线</td>
<td align="center">可通知其它玩家</td>
</tr>
<tr>
<td align="center">onReconn</td>
<td align="center">玩家重连</td>
<td align="center">更新一些自定义数据到本玩家，并通知其它玩家</td>
</tr>
<tr>
<td align="center">onKicked</td>
<td align="center">玩家被踢出房间</td>
<td align="center">-</td>
</tr>
</tbody>
</table>
<p><strong>Player.java 允许自定义 获取属性方法、修改属性方法、监听属性方法</strong></p>
<p>例如，如果云端代码需要修改玩家的hp属性，需要在 <code>Player.java</code> 添加方法：</p>
<pre><code>@BmobGameSDKHook
public native void setHp(int hp);
</code></pre>
<p>如果需要获取玩家的position属性，添加方法：</p>
<pre><code>@BmobGameSDKHook
public native float[] getPosition();
</code></pre>
<p>需要监听玩家的position属性变动，添加方法：</p>
<pre><code>@BmobGameSDKHook
strictfp void onUpdate_Position() {
    // TODO 与当前安全区进行计算，是否扣除玩家血量
}
</code></pre>
<p>需要处理客户端的 <code>Action</code>, 如客户端上报击中其它玩家，<code>Action</code> 为 <code>Damage</code>，添加方法</p>
<pre><code>@BmobGameSDKHook
public void onAction_Damage(byte[] damage) {
    // 使用setHp修改被击中玩家的血量，如果&lt;=0，则判定死亡，通知所有用户
}
</code></pre>
<h3 id="_7">代码节选<a class="headerlink" href="#_7" title="Permanent link">&para;</a></h3>
<ul>
<li>Room.java的代码很简单，只在房间创建、开始、销毁等时候进行Bmob数据库的操作</li>
</ul>
<p><img alt="Room.java" src="//bmob-cdn-14496.b0.upaiyun.com/2018/03/02/edb9d14640f45beb801d0f9b53bb3008.png" title="Room.java" /></p>
<hr />
<ul>
<li>Player.java的代码承担了大多数的游戏逻辑，例如下面是某玩家上报击中另一个玩家时的处理器</li>
</ul>
<p><img alt="Player.java" src="//bmob-cdn-14496.b0.upaiyun.com/2018/03/02/e3ecabaa40bd942a8077829cd35b44f1.jpg" title="Player.java" /></p>
<hr />
<ul>
<li>Unity内代码(属性同步)</li>
</ul>
<p><img alt="Player.cs" src="//bmob-cdn-14496.b0.upaiyun.com/2018/03/02/08b21c594085329e80d4b4ddf483561f.png" title="Player.cs" /></p>
<h2 id="_8">打怪游戏改造<a class="headerlink" href="#_8" title="Permanent link">&para;</a></h2>
<h3 id="unity">准备一个单机的Unity游戏<a class="headerlink" href="#unity" title="Permanent link">&para;</a></h3>
<blockquote>
<p>访问 Unity 的 <a href="https://assetstore.unity.com/">Asset Store</a>下载游戏项目，并且Import到 Unity 内。</p>
</blockquote>
<p>本文选择了一款可爱的射击打怪游戏：<a href="https://assetstore.unity.com/packages/essentials/tutorial-projects/survival-shooter-tutorial-40756">Survival Shooter Tutorial</a></p>
<p><img alt="游戏图片" src="//bmob-cdn-13250.b0.upaiyun.com/2018/03/09/460f8bb94008d8358000b5549955ba18.jpg" /></p>
<p>项目导入后的样子：
<img alt="项目图片" src="//bmob-cdn-13250.b0.upaiyun.com/2018/03/09/082832c6407fa5778057916ba7ccc6a8.png" /></p>
<p>绍项目结构简介：</p>
<ul>
<li>
<p>场景上的摆设物体都包括在<strong>Environment</strong>上，比如图上的闹钟、柜子等，它们的<strong>Layer</strong>都设置为了<strong>Shootable</strong>字段，代码在玩家开激光枪、激光碰撞检测时检测到Shootable为Layer的物体才会触发碰撞事件。</p>
</li>
<li>
<p>怪物的生成由<strong>EnemyManage</strong>来控制，能够管理何种怪物在哪个出生点按什么时间间隔出生。</p>
</li>
<li>
<p>怪物主要由三个脚本来管理，分别是<strong>EnemyHealth.cs</strong>（管理怪物的hp，被玩家射击到时扣血，血量小于等于0时死掉）、<strong>EnemyMovement.cs</strong>（管理怪物的移动，用UnityEngine.AI.NavMeshAgent，把玩家的坐标设为目的地，这样怪物会按设置的行走速度自动走向玩家位置）和<strong>EnemyAttack.cs</strong>（管理怪物的自动攻击，按一定的时间间隔进行发招）。</p>
</li>
<li>
<p>玩家也主要由三个脚本来管理，分别是<strong>PlayerHealth.cs</strong>（管理玩家的hp，主要是收到怪物攻击时掉血）、<strong>PlayerMovement.cs</strong>（管理玩家的移动，当键盘按wsad时上下左右的移动）和<strong>PlayerShooting.cs</strong>（管理玩家的射击动作，当鼠标左键点击时对玩家枪口面对的方向发出激光Ray，如果在范围内碰撞检测到了怪物则对怪物进行扣血）。</p>
</li>
</ul>
<p>更详细更完整的细节请看Unity官方的教程</p>
<hr />
<h3 id="_9">开始改造<a class="headerlink" href="#_9" title="Permanent link">&para;</a></h3>
<blockquote>
<p>将玩家角色(和角色控制器)克隆一份，去掉主动操作行为，添加被动展现方法。</p>
</blockquote>
<p>可以在上一步骤中看到项目中只有一个玩家Player，要改造成联网的游戏就需要多个玩家，所以作者把场景中的Player物体克隆一份，命名为Player2，当然控制它的脚本也不能少，克隆克隆克隆！</p>
<p><img alt="" src="//bmob-cdn-13250.b0.upaiyun.com/2018/03/09/585f4a93406d440680223e33d0e2e3a2.png" /></p>
<ol>
<li>Player2Health.cs：
   因为Player2Health控制的是其他玩家的血量，所以把玩家收到怪物攻击时减的血量设为0，让其他玩家的血量不受本地控制。</li>
<li>
<p>Player2Movement.cs：
    删掉根据键盘的操作引起的移动，加上传入数据时的操作角色移动方法。</p>
<p>```
//  移动到相应坐标
public void MoveTo(float x, float z){
    playerRigidbody.MovePosition (new Vector3(x, playerRigidbody.position.y,z));
    Animating (x, z);
}</p>
<p>//  旋转到相应角度
public void TurnTo(float y){
    transform.eulerAngles = new Vector3 (0, y, 0);
}
```</p>
</li>
<li>
<p>Player2Shooting.cs：
 删掉根据鼠标的操作引起的射击，加上传入射击指令时的方法，考虑到网络延时原因，是否射中怪物的判断不由这里判断，这个射击方法给怪物的伤害要设置为0，仅显示出UI效果。</p>
</li>
</ol>
<p>以上改好后再把对应的脚本替换掉原脚本放到Player2物体上，将物体拖进Project一栏中，这样物体就变成预设物体，可以随时调用啦。除了克隆、修改玩家之外，还需要修改一些细节：</p>
<ul>
<li>更改怪物的移动方式：
上面我们有提到怪物是根据玩家的位置来自动寻路的，那现在有两个玩家了怎么办呢？根据玩游戏的经验告诉我们，怪物会跟着离他更近的玩家走哟。下面贴出代码：</li>
</ul>
<pre><code>// UnityEngine.AI.NavMeshAgent nav;
// nav = GetComponent &lt;UnityEngine.AI.NavMeshAgent&gt; ();
void Update ()
{
    // If the enemy and the player have health left...
    if(enemyHealth.currentHealth &gt; 0)
    {
        Vector3 enemyPosition = transform.position, 
                tempPosition;
        float minDist = float.MaxValue, 
                tempFloat;
        Vector3 target = Vector3.zero;
        for (int i = 0; i &lt; targetHealths.Length; i++) {
            if (targetHealths [i].currentHealth &gt; 0) {
                tempPosition = trackTargets [i].position;
                tempFloat = Vector3.Distance (enemyPosition, tempPosition);
                if (tempFloat &lt; minDist) {
                    minDist = tempFloat;
                    target = tempPosition;
                }
            }
        }
        if (minDist != float.MaxValue) {
            // ... set the destination of the nav mesh agent to the player.
            nav.SetDestination (target);
        }
    }
    // Otherwise...
    else
    {
        // ... disable the nav mesh agent.
        nav.enabled = false;
    }
}
</code></pre>

<ul>
<li>更改怪物受到伤害减血的触发方式：
上面提到，其他玩家射击到怪物的事件不能在我这里减血，那么怪物的血量怎么控制呢，我把EnemyManager.cs的脚本改了下，把生成的每个怪物都命名，当检测到射击时，把我伤害的怪物的名称发送给其他玩家，就能同步好每个怪物的血量了。</li>
</ul>
<h3 id="bmob-game-sdk">结合Bmob Game Sdk<a class="headerlink" href="#bmob-game-sdk" title="Permanent link">&para;</a></h3>
<ol>
<li>访问 <a href="https://game.bmob.cn/">BGS官网</a>，注册账号并下载 Unity SDK、GameCloud SDK;</li>
<li>将 BmobGame_UnitySDK_vx.x.x_xxxxxx.unitypackage Import 到Unity内;</li>
<li>修改SDK，将游戏开始跳转的 Scene 改为本游戏的场景"_Complete-Game/_Complete-Game";</li>
</ol>
<p><code>SceneManager.LoadSceneAsync ("_Complete-Game/_Complete-Game");</code></p>
<ol>
<li>在 Demo Scene 进行SDK的初始化，绑定 delegate 用于处理各种通知;</li>
<li>将处理事件转发的脚本绑定给本地角色Player，将Player的移动、旋转、hp等数据，调用SDK接口同步到服务器;</li>
</ol>
<p>```
    void Update ()
    {
        BmobGame.UpdateFrame ();
        if (isOver)
            return;
        Vector3 position = transform.position;</p>
<pre><code>    BmobGame.EditMyStatus ("position", new float[]{ position.x, position.z });
    BmobGame.EditMyStatus ("rotation", transform.eulerAngles.y);
    BmobGame.EditMyStatus ("hp", GetComponent&lt;PlayerHealthBase&gt;().currentHealth&lt;0?0:GetComponent&lt;PlayerHealthBase&gt;().currentHealth);
}
</code></pre>
<p>```</p>
<ol>
<li>将 Player 的瞬时动作射击、射中的怪物名通过transfer接口直接发送到其他玩家;</li>
</ol>
<p>```
    // Game_BmobSDKTest里面SendFireEvent和SendDamageEvent方法，
    // 都是把传来的参数转成byte数组（数组第一位设为事件类别），
    // 通过transfer接口传递数组给其他玩家：BmobGame.SendTransferToAllExceptSelf (notify);</p>
<pre><code>// Game_BmobSDKTest mBGS;
// mBGS = GetComponentInParent&lt;Game_BmobSDKTest&gt; ();

// 把发射起点、角度、长度，用transfer接口传
mBGS.SendFireEvent (transform.position.x, transform.position.z, transform.eulerAngles.y, range);

// 把射中的怪物名发送出去，用transfer接口传
mBGS.SendDamageEvent (shootHit.collider.name);
</code></pre>
<p>```</p>
<ol>
<li>读取服务器同步的数据，渲染其它玩家的位置、角度。获取其它玩家直接发送的瞬时动作，作出射击和射中某个怪物的处理;</li>
</ol>
<p>```
  //对收到其他玩家信息的处理
  void OnOthersGameStatus (int no, ArrayList attrNames, Hashtable status)
    {
        Debug.Log ("Player[" + no + "] game status is changed: " + status.Count);</p>
<pre><code>    if(attrNames.Contains("position")){
        float[] position = status ["position"] as float[];
        mOtherPlayers [no].GetComponent&lt;Player2Movement&gt; ().MoveTo (position [0], position [1]) ;
    }
    if(attrNames.Contains("rotation")){
        float y = (float)(status ["rotation"]);
        mOtherPlayers [no].GetComponent&lt;Player2Movement&gt; ().TurnTo (y) ;
    }
    if(attrNames.Contains("hp")){
        int hp = (int)(status ["hp"]);
        mOtherPlayers [no].GetComponent&lt;Player2Health&gt; ().currentHealth = hp;
    }
}

//对收到transfer接口的信息的处理
void OnTransfer (int fromNo, byte[] data)
{
    Debug.Log ("Get transfer data flag = " + data[0] + " &amp; len = " + data.Length + " &amp; from: " + fromNo);
    switch(data[0]){
    case 1:
        ReceiveFireEvent (fromNo, data);//开火事件
        break;
    case 2:
        ReceiveDamageEvent (fromNo, data);//击中怪物事件
        break;
    }
    Debug.Log ("Player[" + fromNo + "] transfer: " + data [0] + ", len = " + data.Length);
}

//对收到云端通知的处理
void OnCloudNotifyJson(string jsonStr){
    Debug.Log ("Handle cloud notify: " + jsonStr);
    JSONNode json = JSON.Parse (jsonStr);
    if (json == null) {
        return;
    }
    string a = json ["action"];
    if (a == null || a.Length == 0) {
        return;
    }
    if ("gameover".Equals (a)) {
        // 游戏结束，3秒后回到房间
        Invoke ("BackToRoom", 3);
    }
}
</code></pre>
<p>```</p>
<ol>
<li>在 BGS官网 登录管理后台，创建游戏，修改服务器运行配置，包括：每秒帧率(默认60Hz)、房间最多玩家数 (2个或以上);</li>
<li>修改 玩家属性配置，设置各个属性的名称、类型、长度、值域、由云端/客户端编辑、其它玩家是否可见等。我这里仅有hp、position和rotation。</li>
</ol>
<pre><code>&quot;player&quot;: {                         // 玩家的相关信息
    &quot;attributes&quot;: {                 // 玩家在游戏内的属性，下面的都是示例，实际情况由开发者自定义
        &quot;hp&quot;: {                     // 玩家的HP    
            &quot;type&quot;: &quot;int&quot;,          // HP属性类型为数字
            &quot;max&quot;: 101              // HP的上限，int类型的属性，都可以设置其max，设置得越紧密，运行效率越高
        },
        &quot;position&quot;: {
            &quot;type&quot;: &quot;float[]&quot;,
            &quot;count&quot;: 2,
            &quot;editable&quot;: true,
            &quot;export&quot;: true
        },
        &quot;rotation&quot;: {
            &quot;type&quot;: &quot;float&quot;,
            &quot;editable&quot;: true,
            &quot;export&quot;: true
        }
    }
}
</code></pre>

<p>10 . 打开 Eclipse 或 Android Studio，创建Java项目，导入 BmobGame_JavaCloud_vx.x.x_xxxxxx.jar，并创建 Player.java 和 Room.java，分别继承自 PlayerBase.class 和 RoomBase.class 后，编写游戏逻辑代码。</p>
<p><strong>Player.java :</strong></p>
<pre><code>package cn.bmob.gamesdk.server.been;

import cn.bmob.gamesdk.server.api.BmobGameSDKHook;
import cn.bmob.gamesdk.server.api.JSON;
import cn.bmob.gamesdk.server.api.PlayerBase;

public class Player extends PlayerBase {
    @BmobGameSDKHook
    public native int getHp();

    @BmobGameSDKHook
    public strictfp void onUpdate_Hp() {
        for (Player p : roommates)
            if (p.getHp() != 0)
                return;
        gameOver();
    }

    private final void gameOver() {
        sendToAll(JSON.toJson(&quot;action&quot;, &quot;gameover&quot;).toString().getBytes());
        room.dispatchGameOver();
    }
}

</code></pre>

<p><strong>Room.java :</strong></p>
<pre><code>package cn.bmob.gamesdk.server.been;

import cn.bmob.gamesdk.server.api.RoomBase;

public class Room extends RoomBase{
}
</code></pre>

<p>11 . 打包运行游戏，就可以多人同时在线对战啦~</p>
<h2 id="_10">五子棋/象棋匹配对战<a class="headerlink" href="#_10" title="Permanent link">&para;</a></h2>
<p>如何在1小时内将单机下棋游戏改造成多人联网实时对战小游戏</p>
<p><img alt="小程序二维码" src="//bmob-cdn-12841.b0.upaiyun.com/2018/05/04/ef8b1dd640626c6080af0508497c8c96.png" /></p>
<hr />
<h3 id="1">1.获取 <a href="//game.bmob.cn">比目游戏云服务</a> (下称 官网)的账号；<a class="headerlink" href="#1" title="Permanent link">&para;</a></h3>
<h3 id="2-sdk">2. 在官网下载 <strong>微信小游戏SDK</strong>，导入到原有的单机下棋项目中；<a class="headerlink" href="#2-sdk" title="Permanent link">&para;</a></h3>
<h3 id="3-sdk-appkey">3. 初始化sdk，第一个参数修改为官网获取的 AppKey，第二个参数可先不填，要做第四个步骤获得。<a class="headerlink" href="#3-sdk-appkey" title="Permanent link">&para;</a></h3>
<pre><code>import BGS from '../../js/bmobgamesdk/bgsapi';//根据你自己的存放路径更改
let model = BGS.instance;

model.Init('3f729baax0', 'ws://139.159.220.251:29175', function (succ, msg) {
  if (succ) {
    // 用bmob小程序sdk进行登录注册
    // _getUser(listener);
  } else{
    // 提醒失败，并给重新init的按钮
  }
});
</code></pre>
<h3 id="4-bgsinstanceinit">4. 创建房间，获得Bgs.instance.Init的第二个参数 ###<a class="headerlink" href="#4-bgsinstanceinit" title="Permanent link">&para;</a></h3>
<pre><code>import BGS from '../../js/bmobgamesdk/bgsapi';//根据你自己的存放路径更改
let model = BGS.instance;

var userId =  Bmob.User.current().id;
model.CreateRoom(userId, 2, function(isOK, res) {
        console.log("res &gt;", res);
        if (isOK) {
          var roomInfo = res.roomInfo;
          console.log('对战开房成功', _data);
          // 创建房间成功，跳转游戏房间页面，别忘了把房间信息roomInfo传递过去
        } else {
          common.showModal('对战开房失败，' + res);
        }
      });
</code></pre>
<p>运行游戏，打开network抓包，创建一个房间，查看这个操作的返回结果，返回结果为</p>
<pre><code>{
    "address": "a.b.c.d", // 服务器ip
    "roomInfo": {
        "ports": {
            "websocket": efgh // 服务器端口
        },
        "rid": xxx, // 房间id
        "joinKey": yyy // 房间密匙
    }
}
</code></pre>
<p>这样，你就获得了初始化sdk的第二个参数，是 <strong>ws://a.b.c.d:efgh</strong> 这样的格式     </p>
<h3 id="5">5. 加入房间，初始化监听器<a class="headerlink" href="#5" title="Permanent link">&para;</a></h3>
<pre><code>import BGS from '../../js/bmobgamesdk/bgsapi';//根据你自己的存放路径更改
let model = BGS.instance;

if (this.isConnected)
  return;
t('连接房间');
this.mRoomActListener = this.onRoomAction.bind(this);
this.mOfflineListener = this.onOffline.bind(this);
model.RegistRoomActListener(this.mRoomActListener);// 注册系统通知监听，详细参考官网下载的demo
model.RegistOfflineListener(this.mOfflineListener);// 注册掉线通知监听

let emptyFun = function() {};
model.SetGameRuntimeListeners(
  emptyFun,//这三个监听器本游戏中没有涉及
  emptyFun,
  emptyFun,
  this.onTransfer.bind(this),// 玩家间交互信息的监听器
  this.onCloudNotify.bind(this)//云端代码通知的监听器
);

// 加入房间
// 这里的roomData就是创建房间时让你保存的roomInfo啦
model.JoinRoom(that.roomData.rid, that.roomData.joinKey, userId, model.get('seatKey'), function(isOK, data) {
  if (isOK) {
    common.toast('加入房间成功');
    console.log("房间信息:", data);

    let
      playerCount = data.playerCount,
      no = data.no,
      isPlaying = data.isPlaying,
      players = data.players,
      masterId = data.master;

    // 根据返回的房间信息做些保存或处理，这里不详细写出来，大家根据自己的情况灵活变通...

    if (data.seatKey)
      model.set('seatKey', data.seatKey);
    that.isConnected = true;

    return;
  }

  //加入房间失败
  if (data.indexOf("204") &gt; -1)
    data = "房间已关闭";
  else if (data.indexOf("206") &gt; -1)
    data = "房间已满员";
  else if (data.indexOf("201") &gt; -1)
    data = "未知错误";
  else if (data.indexOf("203") &gt; -1)
    data = "没有登陆";
  else if (data.indexOf("208") &gt; -1)
    data = "游戏中";
  else if (data.indexOf("204") &gt; -1)
    data = "房间不存在";
  else if (data.indexOf("202") &gt; -1)
    data = "参数错误";

  console.log('加入房间失败:', data);
}.bind(this));

// 收到客户端的回调
onTransfer(no, res) {
    console.log("收到客户端的回调:" + no, res)
    let flag = res.shift();
    switch (flag) {
      case 1: // 下棋
        t('收到客户端的下棋数据');
        t(res);
        break;
      case 2: // 被请求悔棋
        // ...

    }
},
// 收到云端代码服务端的回调
onCloudNotify(notify) {
   notify = JSON.parse(model.bytesToString(notify, 0, notify.length));
   console.log("收到服务器的回调:", notify);
  // ...
},
</code></pre>
<h3 id="6">6. 实现下棋数据的实时交互<a class="headerlink" href="#6" title="Permanent link">&para;</a></h3>
<pre><code>// 玩家之间交互数据，上面的onTransfer会收到对方发送的
// 要以byte数组形式，一般把数组的第一位作为自定义交互类型flag，后面的为要交互的数据
model.SendTransferToAllExceptSelf([1, ...]);

// sdk特别提供了把string和byte数组互转的方法
model.stringToBytes('string'); // string转byte[]
model.model.bytesToString(bs, 0, bs.length); // byte[]转string

// 调用云端代码，参数为云端代码方法名
model.CloudAction('Ready');
</code></pre>
<h3 id="7">7. 实现云端代码逻辑<a class="headerlink" href="#7" title="Permanent link">&para;</a></h3>
<p>打开 Eclipse 或 Android Studio，创建Java项目，导入 BmobGame_JavaCloud_vx.x.x_xxxxxx.jar，并创建 Player.java 和 Room.java，分别继承自 PlayerBase.class 和 RoomBase.class 后，编写游戏逻辑代码。写好后提交到官网管理后台的<strong>云函数</strong>处。
这两个java文件的编写主要查看[另一篇教程][2]。</p>
<h3 id="8">8. 离开房间<a class="headerlink" href="#8" title="Permanent link">&para;</a></h3>
<pre><code>  //生命周期函数--监听页面卸载
  onUnload: function() {
    if (this.isConnected) {
      // model.SendTransferToAllExceptSelf([4]);// 向对方发送离开信息
      model.UnregistOfflineListener(this.mOfflineListener);
      model.StopGameRuntimeListener();
      this.mOfflineListener = null;
      model.QuitRoom();
    }
 ｝
</code></pre>
<hr />
<h2 id="_11">贪吃蛇大作战<a class="headerlink" href="#_11" title="Permanent link">&para;</a></h2>
<p>如果以下方式无法开始游戏</p>
<ul>
<li>由于开发时间仓促，如果游戏出现逻辑性问题，那才是正常的</li>
<li>如果有时候进不去游戏，或者创建房间失败，可能是游戏正在维护，也可能是因为已经终止内测</li>
<li>如果你还是很想反馈bug，请联系客服QQ：2093289624</li>
</ul>
<h3 id="_12">链接<a class="headerlink" href="#_12" title="Permanent link">&para;</a></h3>
<p><a href="http://game.bmob.cn/static/demo/hydra/index.html">Hydra对战</a></p>
<h3 id="_13">二维码<a class="headerlink" href="#_13" title="Permanent link">&para;</a></h3>
<p><img alt="Hydra对战" src="https://bmob-cdn-18902.b0.upaiyun.com/2018/05/08/ba758ddd40f3db0a80c26394ff31254b.png" /></p>
                </div>
            </div>
        </div>

        
            <script>var base_url = '../..';</script>
            <script src="../../js/jquery-1.10.2.min.js"></script>
            <script src="../../js/bootstrap-3.0.3.min.js"></script>
            <script src="../../js/highlight.pack.js"></script>
            <script src="../../js/main.js"></script>
            <script src="../../js/base.js"></script>

        <div id="go-top"><i class="fa fa-chevron-up"></i></div>
        <a href="https://docs.bmob.cn/data/Android/a_faststart/doc/index.html" id="back" target="_blank">返回 <br> 旧版</a>
    </body>

</html>